package main

import (
	"context"
	"encoding/json"
	"fmt"
	"github.com/valyala/fasthttp"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/exporters/jaeger"
	"go.opentelemetry.io/otel/propagation"
	"go.opentelemetry.io/otel/sdk/resource"
	"go.opentelemetry.io/otel/sdk/trace"
	semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
	"sync"
	"time"
)

const (
	traceName = "mxshop-otel"
)

var tp *trace.TracerProvider

func funcA(ctx context.Context, wg *sync.WaitGroup) {

	defer wg.Done()
	tracer := otel.Tracer(traceName)
	spanCtx, span := tracer.Start(ctx, "func-a")
	span.SetAttributes(attribute.String("name", "funca"))
	time.Sleep(time.Second)
	fmt.Println("trace:", span.SpanContext().TraceID(), span.SpanContext().SpanID())

	request := fasthttp.AcquireRequest()
	request.SetRequestURI("http://127.0.0.1:8090/server")
	request.Header.SetMethod("GET")
	//拿起传播器
	p := otel.GetTextMapPropagator()
	headers := make(map[string]string)
	p.Inject(spanCtx, propagation.MapCarrier(headers))

	for k, v := range headers {
		request.Header.Set(k, v)
	}

	fclient := fasthttp.Client{}
	fresponse := fasthttp.Response{}
	_ = fclient.Do(request, &fresponse)

	span.End()
}

func funcC(ctx context.Context, wg *sync.WaitGroup) {

	defer wg.Done()
	tracer := otel.Tracer(traceName)
	_, span := tracer.Start(ctx, "func-c")
	span.SetAttributes(attribute.String("name", "funcC"))
	time.Sleep(time.Second)
	fmt.Println("trace:", span.SpanContext().TraceID(), span.SpanContext().SpanID())

	request := fasthttp.AcquireRequest()
	request.SetRequestURI("http://127.0.0.1:8090/server1")
	request.Header.SetMethod("GET")
	//拿起传播器
	//p := otel.GetTextMapPropagator()
	//headers := make(map[string]string)
	//p.Inject(spanCtx, propagation.MapCarrier(headers))

	request.Header.Set("trace-id", span.SpanContext().TraceID().String())
	request.Header.Set("span-id", span.SpanContext().SpanID().String())

	//for k, v := range headers {
	//	request.Header.Set(k, v)
	//}

	fclient := fasthttp.Client{}
	fresponse := fasthttp.Response{}
	_ = fclient.Do(request, &fresponse)

	span.End()
}
func funcB(ctx context.Context, wg *sync.WaitGroup) {

	defer wg.Done()
	tracer := otel.Tracer(traceName)
	_, span := tracer.Start(ctx, "func-b")
	span.SetAttributes(attribute.String("name", "funcb"))

	type _LogStruct struct {
		CurrentTime time.Time `json:"current_time"`
		PassWho     string    `json:"pass_who"`
		Name        string    `json:"name"`
	}

	b, _ := json.Marshal(_LogStruct{
		CurrentTime: time.Now(),
		PassWho:     "bobby",
		Name:        "func-b",
	})
	span.SetAttributes(attribute.Key("这是测试日志的Key").String(string(b)))
	time.Sleep(time.Second)
	span.End()
}

func funcD(ctx context.Context, wg *sync.WaitGroup) {

	defer wg.Done()
	tracer := otel.Tracer(traceName)
	spanCtx, span := tracer.Start(ctx, "func-d")
	span.SetAttributes(attribute.String("name", "funcD"))

	fmt.Println("trace:", span.SpanContext().TraceID(), span.SpanContext().SpanID())

	request := fasthttp.AcquireRequest()
	request.SetRequestURI("http://127.0.0.1:8090/serverdb")
	request.Header.SetMethod("GET")
	//拿起传播器
	p := otel.GetTextMapPropagator()
	headers := make(map[string]string)
	p.Inject(spanCtx, propagation.MapCarrier(headers))

	for k, v := range headers {
		request.Header.Set(k, v)
	}

	fclient := fasthttp.Client{}
	fresponse := fasthttp.Response{}
	_ = fclient.Do(request, &fresponse)
	time.Sleep(time.Second)
	span.End()
}

func tracerProvider() error {
	url := "http://127.0.0.1:14268/api/traces" //这个是jeager对应的地址
	exporter, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(url)))
	if err != nil {
		panic(err)
	}

	tp = trace.NewTracerProvider(
		trace.WithBatcher(exporter),
		trace.WithResource(resource.NewWithAttributes(
			semconv.SchemaURL,
			//设置trace的名称，不设置默认显示文件名
			semconv.ServiceNameKey.String("mxshop-func"),
		)),
	)
	otel.SetTracerProvider(tp)
	otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
	return nil
}

func main() {

	_ = tracerProvider()
	ctx, cancel := context.WithCancel(context.Background())
	defer func(ctx context.Context) {
		ctx, cancel = context.WithTimeout(ctx, time.Second*5)
		defer cancel()
		if err := tp.Shutdown(ctx); err != nil {
			panic(err)
		}
	}(ctx)

	tracer := otel.Tracer(traceName)
	spanCtx, span := tracer.Start(ctx, "func-main")

	wg := &sync.WaitGroup{}
	wg.Add(2)
	go funcB(spanCtx, wg)
	go funcA(spanCtx, wg)

	wg.Wait()

	time.Sleep(time.Second)
	span.End()
}
